package com.blog.controller;

import com.alibaba.fastjson.JSON;
import com.blog.common.Result;
import com.blog.mapper.BlogMapper;
import com.blog.pojo.Blog;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * 博客全局搜索
 */
@Slf4j
@RestController
@RequestMapping("/Elasticsearch")
public class ElasticsearchController {

    @Autowired
    private BlogMapper blogMapper;

    //ES高级客户端
    private RestHighLevelClient client;

    @Value("${es.eshost}")
    private String esHost;

    /**
     * Elasticsearch全局搜索
     * @param titleOrDescriptionOrContent 博客的标题或描述或内容
     * @return Result<List<Blog>>
     * @throws Exception
     */
    @GetMapping
    public Result<List<Blog>> search(String titleOrDescriptionOrContent) throws Exception {
        //------------------创建httpHost和客户端------------------
        HttpHost host = HttpHost.create(esHost);
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        //-----------------------创建属性索引---------------------
        if (!this.isExistsIndex("blogs")){//索引不存在
            //创建请求对象
            CreateIndexRequest request = new CreateIndexRequest("blogs");
            //设置请求中的参数
            String json = "{\n" +
                    "    \"mappings\": {\n" +
                    "        \"properties\": {\n" +
                    "            \"blogId\": {\n" +
                    "                \"type\": \"keyword\"\n" +
                    "            },\n" +
                    "            \"title\": {\n" +
                    "                \"type\": \"text\",\n" +
                    "                \"analyzer\": \"ik_max_word\",\n" +
                    "                \"copy_to\": \"all\"\n" +
                    "            },\n" +
                    "            \"content\": {\n" +
                    "                \"type\": \"text\",\n" +
                    "                \"analyzer\": \"ik_max_word\",\n" +
                    "                \"copy_to\": \"all\"\n" +
                    "            },\n" +
                    "            \"description\": {\n" +
                    "                \"type\": \"text\",\n" +
                    "                \"analyzer\": \"ik_max_word\",\n" +
                    "                \"copy_to\": \"all\"\n" +
                    "            },\n" +
                    "            \"all\": {\n" +
                    "                \"type\": \"text\",\n" +
                    "                \"analyzer\": \"ik_max_word\"\n" +
                    "            }\n" +
                    "        }\n" +
                    "    }\n" +
                    "}";
            request.source(json, XContentType.JSON);
            //创建索引
            client.indices().create(request, RequestOptions.DEFAULT);
        }else {
            log.info("该索引已经存在！");
        }
        //-----------------------创建批量文档---------------------
        List<Blog> blogList = blogMapper.selectList(null);
        BulkRequest bulkRequest = new BulkRequest();
        for (Blog blog : blogList) {
            //添加id
            IndexRequest request = new IndexRequest("blogs").id(blog.getBlogId().toString());
            //添加请求体数据
            String json = JSON.toJSONString(blog);
            request.source(json, XContentType.JSON);
            bulkRequest.add(request);
        }
        client.bulk(bulkRequest, RequestOptions.DEFAULT);
        //-----------------------按条件查询-----------------------
        //添加index
        SearchRequest request = new SearchRequest("blogs");
        //创建builder
        SearchSourceBuilder searchSourceBuilder= new SearchSourceBuilder();
        //title，description，content都已经加入all当中（创建索引的时候）
        //设置匹配值
        searchSourceBuilder.query(QueryBuilders.matchQuery("all",titleOrDescriptionOrContent));
        request.source(searchSourceBuilder);
        //得到response
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //获得所有的命中数据
        SearchHits hits = response.getHits();
        List<Blog> blogSearchResult = new ArrayList<>();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            //System.out.println(source);
            //json数据转对象
            Blog blog = JSON.parseObject(source, Blog.class);
            //log.info("blog:{}",blog);
            //结果放入blogSearchResult集合
            blogSearchResult.add(blog);
        }
        //------------------自己管理client，记得关闭----------------
        client.close();

        return Result.success(blogSearchResult);
    }

    /**
     * 判断指定的索引名是否存在
     * @param indexName 索引名
     * @return  存在：true; 不存在：false;
     */
    public boolean isExistsIndex(String indexName) throws Exception {
        //这里引入的是低级客户端的包，网上搜的判断代码。
        GetIndexRequest existsRequest = new GetIndexRequest();
        existsRequest.indices(indexName);
        boolean exists = client.indices().exists(existsRequest, RequestOptions.DEFAULT);
        return exists;
    }
}
